﻿using Common;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace Linguist.Acoustic.Tiedstate
{
    /// <summary>
    /// Manages HMMs. This HMMManager groups {@link Linguist.Acoustic.HMM HMMs} together by their {@link
    /// Linguist.Acoustic.HMMPosition position} with the word.
    /// </summary>
    public class HMMManager : IEnumerable<IHMM>, IHMMManager
    {
        private List<IHMM> allHMMs = new List<IHMM>();
        private Dictionary<HMMPosition, Dictionary<IUnit, IHMM>> hmmsPerPosition = new Dictionary<HMMPosition, Dictionary<IUnit, IHMM>>(); ///HMMPosition.class

        public HMMManager () 
        {
            foreach (HMMPosition pos in Enum.GetValues(typeof(HMMPosition)))
            {
                if (hmmsPerPosition.ContainsKey(pos))
                    hmmsPerPosition[pos] = new Dictionary<IUnit, IHMM>();
                else
                    hmmsPerPosition.Add(pos, new Dictionary<IUnit, IHMM>());
            }
        }

        /**
        /// Put an HMM into this manager
         *
        /// @param hmm the hmm to manage
         */
        public void put(IHMM hmm) 
        {
            HMMPosition pos = hmm.getPosition();
            IUnit unit = hmm.getUnit();
            if(hmmsPerPosition[pos].ContainsKey(unit))
                hmmsPerPosition[pos][unit] = hmm;
            else
                hmmsPerPosition[pos].Add(hmm.getUnit(), hmm);
            allHMMs.Add(hmm);
        }


        /**
        /// Retrieves an HMM by position and unit
         *
        /// @param position the position of the HMM
        /// @param unit     the unit that this HMM represents
        /// @return the HMM for the unit at the given position or null if no HMM at the position could be found
         */
        public IHMM get(HMMPosition position, IUnit unit) 
        {
            Dictionary<IUnit, IHMM> units = hmmsPerPosition[position];
            if (units == null || units.Count == 0 || !units.ContainsKey(unit))
                return null;
            return units[unit];
        }


        /**
        /// Gets an iterator that iterates through all HMMs
         *
        /// @return an iterator that iterates through all HMMs
         */
        public IEnumerator<IHMM> iterator() {
            return allHMMs.GetEnumerator();
        }


        /**
        /// Returns the number of HMMS in this manager
         *
        /// @return the number of HMMs
         */
        private int getNumHMMs() 
        {
            int count = 0;

            foreach (Dictionary<IUnit, IHMM> map in hmmsPerPosition.Values) 
            {
                if (map != null)
                    count += map.Count;
            }
            return count;
        }


        /**
        /// Log information about this manager
         *
        /// @param logger logger to use for this logInfo
         */
        public void logInfo() 
        {
            Trace.WriteLine("HMM Manager: " + getNumHMMs() + " hmms");
        }


        IEnumerator<IHMM> IEnumerable<IHMM>.GetEnumerator()
        {
            throw new NotImplementedException();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            throw new NotImplementedException();
        }
    }
}
